
package org.apache.solr.update;


import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrEventListener;
import org.apache.solr.core.SolrInfoMBean;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.util.plugin.SolrCoreAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <code>UpdateHandler</code> handles requests to change the index
 * (adds, deletes, commits, optimizes, etc).
 *
 * @since solr 0.9
 */

public abstract class UpdateHandler implements SolrInfoMBean {
//List<?> list = Collections.synchronizedList(new ArrayList<?>());

    protected final static Logger log = LoggerFactory.getLogger(UpdateHandler.class);
    protected final SolrCore core;
    protected final IndexSchema schema;
    protected final SchemaField idField;
    protected final FieldType idFieldType;
    protected List<SolrEventListener> commitCallbacks = Collections.synchronizedList(new ArrayList<SolrEventListener>());
    protected List<SolrEventListener> softCommitCallbacks = Collections.synchronizedList(new ArrayList<SolrEventListener>());
    protected List<SolrEventListener> optimizeCallbacks = Collections.synchronizedList(new ArrayList<SolrEventListener>());
    protected UpdateLog ulog;

    /**
     * Called when a SolrCore using this UpdateHandler is closed.
     */
    public abstract void decref();

    /**
     * Called when this UpdateHandler is shared with another SolrCore.
     */
    public abstract void incref();

    private void parseEventListeners() {
        final Class<SolrEventListener> clazz = SolrEventListener.class;
        final String label = "Event Listener";

        for (PluginInfo info : core.getSolrConfig().getPluginInfos(SolrEventListener.class.getName())) {

            String event = info.attributes.get("event");
            switch (event) {
                case "postCommit":
                    {
                        SolrEventListener obj = core.createInitInstance(info, clazz, label, null);
                        commitCallbacks.add(obj);
                        log.info("added SolrEventListener for postCommit: " + obj);
                        break;
                    }
                case "postOptimize":
                    {
                        SolrEventListener obj = core.createInitInstance(info, clazz, label, null);
                        optimizeCallbacks.add(obj);
                        log.info("added SolrEventListener for postOptimize: " + obj);
                        break;
                    }
            }
        }
    }

    private void initLog() {

        PluginInfo ulogPluginInfo = core.getSolrConfig().getPluginInfo(UpdateLog.class.getName());
        if (ulogPluginInfo != null && ulogPluginInfo.isEnabled()) {
            ulog = new UpdateLog();
            ulog.init(ulogPluginInfo);
            // ulog = core.createInitInstance(ulogPluginInfo, UpdateLog.class, "update log", "solr.NullUpdateLog");
            ulog.init(this, core);
        }
    }

    protected void callPostCommitCallbacks() {
        for (SolrEventListener listener : commitCallbacks) {
            listener.postCommit();
        }
    }

    protected void callPostSoftCommitCallbacks() {
        for (SolrEventListener listener : softCommitCallbacks) {
            listener.postSoftCommit();
        }
    }

    protected void callPostOptimizeCallbacks() {
        for (SolrEventListener listener : optimizeCallbacks) {
            listener.postCommit();
        }
    }

    public UpdateHandler(SolrCore core) {
        this.core = core;
        schema = core.getSchema();
        idField = schema.getUniqueKeyField();
        idFieldType = idField != null ? idField.getType() : null;
        parseEventListeners();
        initLog();
    }

    /**
     * Called when the Writer should be opened again - eg when replication
     * replaces all of the index files.
     *
     * @param rollback IndexWriter if true else close
     * @throws IOException If there is a low-level I/O error.
     */

    public abstract void newIndexWriter(boolean rollback) throws IOException;
    public abstract SolrCoreState getSolrCoreState();
    public abstract int addDoc(AddUpdateCommand cmd) throws IOException;
    public abstract void delete(DeleteUpdateCommand cmd) throws IOException;
    public abstract void deleteByQuery(DeleteUpdateCommand cmd) throws IOException;
    public abstract int mergeIndexes(MergeIndexesCommand cmd) throws IOException;
    public abstract void commit(CommitUpdateCommand cmd) throws IOException;
    public abstract void rollback(RollbackUpdateCommand cmd) throws IOException;
    public abstract void close() throws IOException;
    public abstract UpdateLog getUpdateLog();

    /**
     * NOTE: this function is not thread safe. However, it is safe to call
     * within the
     * <code>inform( SolrCore core )</code> function for
     * <code>SolrCoreAware</code> classes. Outside
     * <code>inform</code>, this could potentially throw a
     * ConcurrentModificationException
     *
     * @see SolrCoreAware
     */
    public void registerCommitCallback(SolrEventListener listener) {
        commitCallbacks.add(listener);
    }

    /**
     * NOTE: this function is not thread safe. However, it is safe to call
     * within the
     * <code>inform( SolrCore core )</code> function for
     * <code>SolrCoreAware</code> classes. Outside
     * <code>inform</code>, this could potentially throw a
     * ConcurrentModificationException
     *
     * @see SolrCoreAware
     */
    public void registerSoftCommitCallback(SolrEventListener listener) {
        softCommitCallbacks.add(listener);
    }

    /**
     * NOTE: this function is not thread safe. However, it is safe to call
     * within the
     * <code>inform( SolrCore core )</code> function for
     * <code>SolrCoreAware</code> classes. Outside
     * <code>inform</code>, this could potentially throw a
     * ConcurrentModificationException
     *
     * @see SolrCoreAware
     */
    public void registerOptimizeCallback(SolrEventListener listener) {
        optimizeCallbacks.add(listener);
    }

    public abstract void split(SplitIndexCommand cmd) throws IOException;
}
